<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 7.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.ico">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.ico">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha256-wiz7ZSCn/btzhjKDQBms9Hx4sSeUYsDrTLg7roPstac=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.css" integrity="sha256-6cQIC71/iBIYXFK+0RHAvwmjwWzkWd+r7v/BX3/vZDc=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/themes/green/pace-theme-minimal.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/pace.min.js" integrity="sha256-gqd7YTjg/BtfqWSwsJOvndl0Bxc8gFImLEkXQT8+qj0=" crossorigin="anonymous"></script>

<script class="next-config" data-name="main" type="application/json">{"hostname":"sumumm.github.io","root":"/","images":"/images","scheme":"Gemini","darkmode":false,"version":"8.19.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":"mac"},"fold":{"enable":true,"height":300},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":true,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content="本文主要是进程——线程取消与清理的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:type" content="article">
<meta property="og:title" content="LV05-02-线程-05-线程取消与清理">
<meta property="og:url" content="https://sumumm.github.io/post/bf8f116.html">
<meta property="og:site_name" content="苏木">
<meta property="og:description" content="本文主要是进程——线程取消与清理的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2023-07-02T13:52:06.000Z">
<meta property="article:modified_time" content="2025-06-13T16:25:56.993Z">
<meta property="article:author" content="苏木">
<meta property="article:tag" content="LV05-操作系统">
<meta name="twitter:card" content="summary">


<link rel="canonical" href="https://sumumm.github.io/post/bf8f116.html">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"https://sumumm.github.io/post/bf8f116.html","path":"post/bf8f116.html","title":"LV05-02-线程-05-线程取消与清理"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>LV05-02-线程-05-线程取消与清理 | 苏木</title>
  








    <script src="/js/browser_tools_disable.js"></script>

  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
<!-- hexo injector head_end start --><link rel="stylesheet" href="https://unpkg.com/hexo-next-tags-plus@latest/lib/tag_plus.css" media="defer" onload="this.media='all'"><!-- hexo injector head_end end --></head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">苏木</p>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">我的学习之路</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>苏木的家</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类页<span class="badge">42</span></a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档页<span class="badge">673</span></a></li><li class="menu-item menu-item-flink"><a href="/flink/" rel="section"><i class="fa fa-link fa-fw"></i>友人帐</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于我</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%80%E3%80%81%E7%BA%BF%E7%A8%8B%E5%8F%96%E6%B6%88"><span class="nav-text">一、线程取消</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E5%8F%96%E6%B6%88%E5%87%BD%E6%95%B0"><span class="nav-text">1. 取消函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-pthread-cancel"><span class="nav-text">1.1 pthread_cancel() </span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">1.1.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#1-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">1.1.2 使用实例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E5%8F%96%E6%B6%88%E7%8A%B6%E6%80%81%E5%8F%8A%E7%B1%BB%E5%9E%8B"><span class="nav-text">2. 取消状态及类型</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-pthread-setcancelstate"><span class="nav-text">2.1 pthread_setcancelstate() </span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.1.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.1.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-pthread-setcanceltype"><span class="nav-text">2.2 pthread_setcanceltype() </span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.2.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.2.2 使用实例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E5%8F%96%E6%B6%88%E7%82%B9"><span class="nav-text">3. 取消点</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-1-%E5%8F%96%E6%B6%88%E7%82%B9%E7%9A%84%E6%A6%82%E5%BF%B5"><span class="nav-text">3.1 取消点的概念</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-%E5%8F%96%E6%B6%88%E7%82%B9%E5%87%BD%E6%95%B0"><span class="nav-text">3.2 取消点函数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-3-%E5%8F%96%E6%B6%88%E7%82%B9%E5%87%BD%E6%95%B0%E6%89%A7%E8%A1%8C%E5%98%9B%EF%BC%9F"><span class="nav-text">3.3 取消点函数执行嘛？</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-4-%E6%B7%BB%E5%8A%A0%E5%8F%96%E6%B6%88%E7%82%B9"><span class="nav-text">3.4 添加取消点</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-4-1-pthread-testcancel"><span class="nav-text">3.4.1 pthread_testcancel() </span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#3-4-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">3.4.1.1 函数说明</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#3-4-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">3.4.1.2 使用实例</span></a></li></ol></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%8C%E3%80%81%E7%BA%BF%E7%A8%8B%E6%B8%85%E7%90%86"><span class="nav-text">二、线程清理</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">1.函数说明</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-pthread-cleanup-push"><span class="nav-text">1.1 pthread_cleanup_push() </span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-pthread-cleanup-pop"><span class="nav-text">1.2 pthread_cleanup_pop() </span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E5%87%BD%E6%95%B0%E4%BD%BF%E7%94%A8"><span class="nav-text">2. 函数使用</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-%E5%87%BD%E6%95%B0%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F"><span class="nav-text">2.1 函数实现方式</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-%E5%87%BD%E6%95%B0%E6%89%A7%E8%A1%8C%E6%9D%A1%E4%BB%B6"><span class="nav-text">2.2 函数执行条件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-3-pthread-exit-%E8%A7%A6%E5%8F%91%E6%B8%85%E7%90%86%E5%87%BD%E6%95%B0%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.3 pthread_exit() 触发清理函数实例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-4-pthread-cancel-%E8%A7%A6%E5%8F%91%E6%B8%85%E7%90%86%E5%87%BD%E6%95%B0%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.4 pthread_cancel() 触发清理函数实例</span></a></li></ol></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="苏木"
      src="/images/avatar.jpg">
  <p class="site-author-name" itemprop="name">苏木</p>
  <div class="site-description" itemprop="description">莫道桑榆晚，为霞尚满天</div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">673</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">42</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
        <span class="site-state-item-count">43</span>
        <span class="site-state-item-name">标签</span>
      </div>
  </nav>
</div>
  <div class="links-of-author animated">
      <span class="links-of-author-item">
        <a href="https://github.com/sumumm" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;sumumm" rel="noopener me" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
  </div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://sumumm.github.io/post/bf8f116.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.jpg">
      <meta itemprop="name" content="苏木">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="苏木">
      <meta itemprop="description" content="莫道桑榆晚，为霞尚满天">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="LV05-02-线程-05-线程取消与清理 | 苏木">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          LV05-02-线程-05-线程取消与清理
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-07-02 21:52:06" itemprop="dateCreated datePublished" datetime="2023-07-02T21:52:06+08:00">2023-07-02</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/" itemprop="url" rel="index"><span itemprop="name">嵌入式开发</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/" itemprop="url" rel="index"><span itemprop="name">01HQ课程体系</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/" itemprop="url" rel="index"><span itemprop="name">LV05-操作系统</span></a>
        </span>
    </span>

  
    <span class="post-meta-break"></span>
    <span class="post-meta-item" title="本文字数">
      <span class="post-meta-item-icon">
        <i class="far fa-file-word"></i>
      </span>
      <span class="post-meta-item-text">本文字数：</span>
      <span>7.7k</span>
    </span>
    <span class="post-meta-item" title="阅读时长">
      <span class="post-meta-item-icon">
        <i class="far fa-clock"></i>
      </span>
      <span class="post-meta-item-text">阅读时长 &asymp;</span>
      <span>28 分钟</span>
    </span>
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody"><p>本文主要是进程——线程取消与清理的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。</p>
<span id="more"></span>

<!-- Photo: none -->

<details class="folding-tag" blue><summary> 点击查看使用工具及版本 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center" width=150px>Windows</td>        <td align="left">windows11</td>    </tr>    <tr>        <td align="center">Ubuntu</td>        <td align="left">Ubuntu16.04的64位版本</td>      </tr>    <tr>        <td align="center">VMware® Workstation 16 Pro</td>        <td align="left">16.2.3 build-19376536</td>      </tr>    <tr>        <td align="center">SecureCRT</td>        <td align="left">Version 8.7.2 (x64 build 2214)   -   正式版-2020年5月14日</td>      </tr>    <tr>        <td align="center">开发板</td>        <td align="left">正点原子 i.MX6ULL Linux阿尔法开发板</td>      </tr>    <tr>        <td align="center">uboot</td>        <td align="left">NXP官方提供的uboot，NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)</td>      </tr>    <tr>        <td align="center">linux内核</td>        <td align="left">linux-4.15(NXP官方提供)</td>      </tr>    <tr>        <td align="center">STM32开发板</td>        <td align="left">正点原子战舰V3(STM32F103ZET6)</td>      </tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看本文参考资料 </summary>
              <div class='content'>
              <table>    <tr><td align="center">参考方向  </td><td align="center">参考原文</td></tr>    <tr><td align="left">---</td><td align="left"><a href="" target="_blank">--- <i class="fa fa-external-link-alt"></i> </a></td></tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看相关文件下载 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center" width=150>---</td>        <td align="left"><a href="" target="_blank">---<i class="fa fa-external-link-alt"></i> </a></td>      </tr></table>
              </div>
            </details>

<h1 id="一、线程取消"><a href="#一、线程取消" class="headerlink" title="一、线程取消"></a><font size=3>一、线程取消</font></h1><h2 id="1-取消函数"><a href="#1-取消函数" class="headerlink" title="1. 取消函数"></a><font size=3>1. 取消函数</font></h2><h3 id="1-1-pthread-cancel"><a href="#1-1-pthread-cancel" class="headerlink" title="1.1 pthread_cancel() "></a><font size=3>1.1 pthread_cancel() </font></h3><h4 id="1-1-1-函数说明"><a href="#1-1-1-函数说明" class="headerlink" title="1.1.1 函数说明"></a><font size=3>1.1.1 函数说明</font></h4><p>在 linux 下可以使用 man pthread_cancel 命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Compile and link with -pthread. */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"><span class="type">int</span> <span class="title function_">pthread_cancel</span><span class="params">(<span class="type">pthread_t</span> thread)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数向一个指定的线程（包括调用此函数的线程）发送取消请求。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li>thread ： pthread_t 类型，参数 thread 指定需要取消的目标线程的线程 ID 。</li>
</ul>
<p><strong>【返回值】</strong> int 类型，成功返回 0 ，失败将返回错误码。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">pthread_cancel(tid);</span><br><span class="line">pthread_cancel(pthread_self());<span class="comment">/* 向自己发送请求*/</span></span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong></p>
<p>（1）发出取消请求之后，函数 pthread_cancel() 立即返回，不会等待目标线程的退出。默认情况下，目标线程也会立刻退出，其行为表现为如同调用了参数为 PTHREAD_CANCELED （其实就是 (void *)-1 ）的 pthread_exit() 函数，但是，线程可以设置自己不被取消或者控制如何被取消后边会介绍，所以 pthread_cancel() 并不会等待线程终止，<strong>仅仅只是提出请求</strong>。</p>
<p>（2）线程也可以向自己发送取消请求。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pthread_cancel(pthread_self());</span><br></pre></td></tr></table></figure>

<h4 id="1-1-2-使用实例"><a href="#1-1-2-使用实例" class="headerlink" title="1.1.2 使用实例"></a><font size=3>1.1.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span><span class="comment">/* pthread_create pthread_exit pthread_cancel */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span> <span class="comment">/* strerror */</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> macro 1 <span class="comment">/* 决定主线程是否发出取消请求 */</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCancel</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="type">int</span> ret;</span><br><span class="line">	<span class="type">pthread_t</span> tid;</span><br><span class="line">	<span class="type">void</span> *retv;</span><br><span class="line">	<span class="comment">/* 1. 创建一个线程 */</span></span><br><span class="line">	ret = pthread_create(&amp;tid, <span class="literal">NULL</span>, (<span class="type">void</span> *)threadCancel, <span class="literal">NULL</span>);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is main thread,ret=%d,tid=%lu\n&quot;</span>, ret, tid);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">2</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		sleep(<span class="number">1</span>);<span class="comment">/* 停留2s后取消创建的新线程*/</span></span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;main thread running!i = %d\n&quot;</span>, i);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 2. 取消线程 */</span></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;cancel thread!\n----------------\n&quot;</span>);</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> macro == 1</span></span><br><span class="line">	pthread_cancel(tid);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">	<span class="comment">/* 3. 回收线程 */</span></span><br><span class="line">	ret = pthread_join(tid, &amp;retv);</span><br><span class="line">	<span class="keyword">if</span>(ret != <span class="number">0</span>)</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;pthread_join error: %s\n&quot;</span>, strerror(ret));</span><br><span class="line">	<span class="comment">/* 这一句将会导致一个段错误 */</span></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;thread ret=%s\n&quot;</span>, (<span class="type">char</span>*)retv);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCancel</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is a new thread!\n&quot;</span>);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;new thread running! i = %d\n&quot;</span>, i);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 由于线程取消，下边这句永远不会执行，所以就无返回值，于是主线程中的回收线程</span></span><br><span class="line"><span class="comment">	   函数就会出现内存访问的错误	*/</span></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;new thread exit!\n&quot;</span>);</span><br><span class="line">	pthread_exit(<span class="string">&quot;new thread return&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>程序中的宏 macro 用于决定主线程是否发出取消请求。</p><ul><li>若 macro 为 1 ，则主线程不会发出线程取消请求。</li><li>若 macro 为 0 ，则主线程进入 for 循环休眠 2s 后发出取消请求。</li></ul><div class="tabs" id="tabname1"><ul class="nav-tabs"><li class="tab active"><a href="#tabname1-1">macro == 1</a></li><li class="tab"><a href="#tabname1-2">macro == 0</a></li></ul><div class="tab-content"><div class="tab-pane active" id="tabname1-1"><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall -l pthread # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">This is main thread,ret=0,tid=140496116229696</span><br><span class="line">This is a new thread!</span><br><span class="line">new thread running! i = 0</span><br><span class="line">main thread running!i = 0</span><br><span class="line">new thread running! i = 1</span><br><span class="line">main thread running!i = 1</span><br><span class="line">cancel thread!</span><br><span class="line">----------------</span><br><span class="line">new thread running! i = 2</span><br><span class="line">段错误 (核心已转储)</span><br></pre></td></tr></table></figure><p>此种情况下，主线程在休眠 2s 后，向新线程发送取消请求，当新线程执行完循环内的 printf 后直接取消线程，所以后边的 pthread_exit() 函数是不会执行的，也就不存在退出码，这也意味着主线程中的线程回收函数 pthread_join() 根本就接收不到 retval 参数，而这又是一个指针变量，这个指针就成为了一个空指针，主线程中访问了一个空指针，自然会出现段错误。</p></div><div class="tab-pane" id="tabname1-2"><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall -l pthread # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">This is main thread,ret=0,tid=140382870578752</span><br><span class="line">This is a new thread!</span><br><span class="line">new thread running! i = 0</span><br><span class="line">main thread running!i = 0</span><br><span class="line">new thread running! i = 1</span><br><span class="line">main thread running!i = 1</span><br><span class="line">cancel thread!</span><br><span class="line">----------------</span><br><span class="line">new thread running! i = 2</span><br><span class="line">new thread running! i = 3</span><br><span class="line">new thread running! i = 4</span><br><span class="line">new thread exit!</span><br><span class="line">thread ret=new thread return</span><br></pre></td></tr></table></figure><p>此种情况为正常运行，主线程和新线程都正常运行完毕。</p></div></div></div><p>【注意事项】</p><p>首先我们需要知道 printf 和 sleep 都属于 Cancellation points 也就是取消点，这个后边会有一节笔记专门记录这个这个的存在导致新线程中 sleep 语句和 printf 语句放置位置的不同就会有不同的情况，若 sleep 在前，当发出取消请求后， printf 不会再执行。</p>
              </div>
            </details>

<h2 id="2-取消状态及类型"><a href="#2-取消状态及类型" class="headerlink" title="2. 取消状态及类型"></a><font size=3>2. 取消状态及类型</font></h2><h3 id="2-1-pthread-setcancelstate"><a href="#2-1-pthread-setcancelstate" class="headerlink" title="2.1 pthread_setcancelstate() "></a><font size=3>2.1 pthread_setcancelstate() </font></h3><h4 id="2-1-1-函数说明"><a href="#2-1-1-函数说明" class="headerlink" title="2.1.1 函数说明"></a><font size=3>2.1.1 函数说明</font></h4><p>在 linux 下可以使用 man pthread_setcancelstate 命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Compile and link with -pthread. */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"><span class="type">int</span> <span class="title function_">pthread_setcancelstate</span><span class="params">(<span class="type">int</span> state, <span class="type">int</span> *oldstate)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>设置调用该函数的线程的取消状态。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li>state ： int 类型，参数 state 中给定的值将会被设置为调用线程的取消状态。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 state 可取的值 </summary>
              <div class='content'>
              <table>    <tr><td align="left" width=150px>PTHREAD_CANCEL_ENABLE </td><td align="left">线程可以取消，这是新创建的线程取消性状态的默认值，所以新建线程以及主线程默认都是可以取消的。</td></tr>    <tr><td align="left" width=150px>PTHREAD_CANCEL_DISABLE</td><td align="left">线程不可被取消，如果此类线程接收到取消请求，则会将请求挂起，直至线程的取消性状态变为PTHREAD_CANCEL_ENABLE。</td></tr></table>
              </div>
            </details>

<ul>
<li>oldstate ： int * 类型，线程之前的取消性状态会保存在参数 oldstate 指向的缓冲区中，如果对之前的状态不感兴趣， Linux 允许将参数 oldstate 设置为 NULL 。</li>
</ul>
<p><strong>【返回值】</strong> int 类型，成功返回 0 ，失败将返回错误码。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, <span class="literal">NULL</span>);<span class="comment">/* 设置为不可被取消 */</span></span><br><span class="line">pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, <span class="literal">NULL</span>);<span class="comment">/* 设置为可被取消 */</span></span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong> pthread_setcancelstate() 函数执行的设置取消性状态和获取旧状态操作，这两步是一个原子操作。</p>
<h4 id="2-1-2-使用实例"><a href="#2-1-2-使用实例" class="headerlink" title="2.1.2 使用实例"></a><font size=3>2.1.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span><span class="comment">/* pthread_create pthread_exit pthread_cancel */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span> <span class="comment">/* strerror */</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> macro 1 <span class="comment">/* 决定新线程中是否设置取消状态 */</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCancel</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="type">int</span> ret;</span><br><span class="line">	<span class="type">pthread_t</span> tid;</span><br><span class="line">	<span class="type">void</span> *retv;</span><br><span class="line">	<span class="comment">/* 1. 创建一个线程 */</span></span><br><span class="line">	ret = pthread_create(&amp;tid, <span class="literal">NULL</span>, (<span class="type">void</span> *)threadCancel, <span class="literal">NULL</span>);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is main thread,ret=%d,tid=%lu\n&quot;</span>, ret, tid);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">2</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		sleep(<span class="number">1</span>);<span class="comment">/* 停留5s后取消创建的新线程*/</span></span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;main thread running!i = %d\n&quot;</span>, i);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 2. 取消线程 */</span></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;cancel thread!\n----------------\n&quot;</span>);</span><br><span class="line">	pthread_cancel(tid);</span><br><span class="line">	<span class="comment">/* 3. 回收线程 */</span></span><br><span class="line">	ret = pthread_join(tid, &amp;retv);</span><br><span class="line">	<span class="keyword">if</span>(ret != <span class="number">0</span>)</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;pthread_join error: %s\n&quot;</span>, strerror(ret));</span><br><span class="line">	<span class="comment">/* 这一句将会导致一个段错误 */</span></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;thread ret=%s\n&quot;</span>, (<span class="type">char</span>*)retv);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCancel</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> macro == 1</span></span><br><span class="line">	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, <span class="literal">NULL</span>);<span class="comment">/* 设置为不可被取消 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is a new thread!\n&quot;</span>);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;new thread running!i = %d\n&quot;</span>, i);</span><br><span class="line">	&#125;</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> macro == 1</span></span><br><span class="line">	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, <span class="literal">NULL</span>);<span class="comment">/* 设置为可被取消 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;new thread exit!\n&quot;</span>);</span><br><span class="line">	pthread_exit(<span class="string">&quot;new thread return&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>程序中主线程进入 for 循环休眠 2s 后发出取消请求，宏 macro 用于决定新线程中是否设置取消状态。</p><ul><li>若 macro 为 1 ，则新线程会设置为不可取消， for 循环执行完毕后，线程才正常结束。</li><li>若 macro 为 0 ，则主线程进入 for 循环休眠 2s 后发出取消请求。</li></ul><div class="tabs" id="tabname2"><ul class="nav-tabs"><li class="tab active"><a href="#tabname2-1">macro == 1</a></li><li class="tab"><a href="#tabname2-2">macro == 0</a></li></ul><div class="tab-content"><div class="tab-pane active" id="tabname2-1"><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall -l pthread # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">This is main thread,ret=0,tid=139966405953088</span><br><span class="line">This is a new thread!</span><br><span class="line">main thread running!i = 0</span><br><span class="line">new thread running!i = 0</span><br><span class="line">main thread running!i = 1</span><br><span class="line">cancel thread!</span><br><span class="line">----------------</span><br><span class="line">new thread running!i = 1</span><br><span class="line">new thread running!i = 2</span><br><span class="line">new thread running!i = 3</span><br><span class="line">new thread running!i = 4</span><br><span class="line">段错误 (核心已转储)</span><br></pre></td></tr></table></figure><p>此种情况下，主线程在休眠 2s 后，向新线程发送取消请求，由于新线程设置了自己不可被取消，所以会执行完自己内部的 for 循环，循环执行完毕后又设置自己为可取消，而下边刚好又出现了 printf 函数（ Cancellation points ），此时线程直接取消，所以线程后边的线程退出函数 pthread_exit() 是不会执行的，也就不存在退出码，这也意味着主线程中的线程回收函数 pthread_join() 根本就接收不到 retval 参数，而这又是一个指针变量，这个指针就成为了一个空指针，主线程中访问了一个空指针，自然会出现段错误。</p><p>其实尝试一下去掉线程退出函数前边的 printf 语句，会发现线程会正常的退出，不会发生段错误。</p></div><div class="tab-pane" id="tabname2-2"><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall -l pthread # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">This is main thread,ret=0,tid=140574419174976</span><br><span class="line">This is a new thread!</span><br><span class="line">main thread running!i = 0</span><br><span class="line">new thread running!i = 0</span><br><span class="line">main thread running!i = 1</span><br><span class="line">cancel thread!</span><br><span class="line">----------------</span><br><span class="line">new thread running!i = 1</span><br><span class="line">段错误 (核心已转储)</span><br></pre></td></tr></table></figure><p>此种情况为主线程发送取消请求后，新线程中遇到 sleep 就直接取消了。</p></div></div></div><p>【注意事项】 printf 和 sleep 都属于 Cancellation points 也就是取消点。</p>
              </div>
            </details>

<h3 id="2-2-pthread-setcanceltype"><a href="#2-2-pthread-setcanceltype" class="headerlink" title="2.2 pthread_setcanceltype() "></a><font size=3>2.2 pthread_setcanceltype() </font></h3><h4 id="2-2-1-函数说明"><a href="#2-2-1-函数说明" class="headerlink" title="2.2.1 函数说明"></a><font size=3>2.2.1 函数说明</font></h4><p>在 linux 下可以使用 man pthread_setcanceltype 命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Compile and link with -pthread. */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"><span class="type">int</span> <span class="title function_">pthread_setcanceltype</span><span class="params">(<span class="type">int</span> type, <span class="type">int</span> *oldtype)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>设置调用该函数的线程的取消类型。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li>type ： int 类型，参数 type 中给定的值将会被设置为调用线程的取消类型。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 type 可取的值 </summary>
              <div class='content'>
              <table>    <tr><td align="left" width=200px>PTHREAD_CANCEL_DEFERRED</td><td align="left">取消请求到来时，线程还是继续运行，取消请求被挂起，直到线程到达某个取消点（cancellation point）为止，这是所有新建线程包括主线程默认的取消性类型。</td></tr>    <tr><td align="left" width=200px>PTHREAD_CANCEL_ASYNCHRONOUS</td><td align="left">可能会在任何时间点取消线程，这种取消性类型应用场景很少。<br>【说明】通常是立即取消，但不一定，这里的立即只是说目标线程不用等执行到属于cancellation point的函数的时候才会取消，它会在获得调度之后立即取消，因为内核调度会有延时，所以并不能保证时间上的“立即”。</td></tr></table>
              </div>
            </details>

<ul>
<li>oldtype ： int * 类型，线程之前的取消类型会保存在参数 oldtype 指向的缓冲区中，如果对之前的状态不感兴趣， Linux 允许将参数 oldtype 设置为 NULL 。</li>
</ul>
<p><strong>【返回值】</strong> int 类型，成功返回 0 ，失败将返回错误码。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, <span class="literal">NULL</span>);<span class="comment">/* 到达某个取消点取消 */</span></span><br><span class="line">pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,<span class="literal">NULL</span>);<span class="comment">/* 立刻取消 */</span></span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong> pthread_setcanceltype() 函数执行的设置取消性类型和获取旧类型操作，这两步是一个原子操作。</p>
<h4 id="2-2-2-使用实例"><a href="#2-2-2-使用实例" class="headerlink" title="2.2.2 使用实例"></a><font size=3>2.2.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span><span class="comment">/* pthread_create pthread_exit pthread_cancel pthread_testcancel pthread_self*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> macro 0</span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCancelType</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="type">pthread_t</span> tid;</span><br><span class="line">	<span class="type">void</span> *retv;</span><br><span class="line">	<span class="comment">/* 1. 创建一个线程 */</span></span><br><span class="line">	ret = pthread_create(&amp;tid, <span class="literal">NULL</span>, (<span class="type">void</span> *)threadCancelType, <span class="literal">NULL</span>);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is main thread,ret=%d,tid=%lu\n&quot;</span>, ret, tid);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">2</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;main thread!i=%d\n&quot;</span>, i);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 2. 申请取消线程 */</span></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;----------------\ncancel thread!\n----------------\n&quot;</span>);</span><br><span class="line">	pthread_cancel(tid);</span><br><span class="line">	<span class="comment">/* 3. 回收线程,若取消成功，这里将会返回错误，然后打印信息 */</span></span><br><span class="line">	ret = pthread_join(tid, &amp;retv);</span><br><span class="line">	<span class="keyword">if</span>(ret != <span class="number">0</span>)</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;pthread_join error: %s\n&quot;</span>, strerror(ret));</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;thread test end, code=%ld\n&quot;</span>, (<span class="type">long</span>)retv);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCancelType</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is a thread test!\n&quot;</span>);</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> macro == 1</span></span><br><span class="line">	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,<span class="literal">NULL</span>);<span class="comment">/* 到达取消点取消 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,<span class="literal">NULL</span>);<span class="comment">/* 立即取消 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> (<span class="type">void</span> *)<span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>程序中的宏 macro 用于配置新线程的取消类型。</p><ul><li>若 macro 为 1 ，则新线程取消类型为 PTHREAD_CANCEL_DEFERRED 。</li><li>若 macro 为 0 ，则新线程取消类型为 PTHREAD_CANCEL_ASYNCHRONOUS 。</li></ul><div class="tabs" id="tabname3"><ul class="nav-tabs"><li class="tab active"><a href="#tabname3-1">macro == 1</a></li><li class="tab"><a href="#tabname3-2">macro == 0</a></li></ul><div class="tab-content"><div class="tab-pane active" id="tabname3-1"><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall -l pthread # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">This is main thread,ret=0,tid=140369903380032</span><br><span class="line">This is a thread test!</span><br><span class="line">main thread!i=0</span><br><span class="line">main thread!i=1</span><br><span class="line">----------------</span><br><span class="line">cancel thread!</span><br><span class="line">----------------</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>此种情况下，主线程在休眠 2s 后，向新线程发送取消请求，新线程设置为了到达取消点取消，下边有一个 while(1) 的死循环，且内部无取消点，这就意味着新线程不会结束，主线程也会阻塞等待新线程结束。可以重开一个终端使用如下命令查看线程：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps -eLf|grep a.out</span><br></pre></td></tr></table></figure></div><div class="tab-pane" id="tabname3-2"><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall -l pthread # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">This is main thread,ret=0,tid=140581044491840</span><br><span class="line">This is a thread test!</span><br><span class="line">main thread!i=0</span><br><span class="line">main thread!i=1</span><br><span class="line">----------------</span><br><span class="line">cancel thread!</span><br><span class="line">----------------</span><br><span class="line">thread test end, code=-1</span><br></pre></td></tr></table></figure><p>此种情况在新线程中设置了线程立即取消，所以即便没有遇到取消点，也会正常的结束线程，主线程也会正常执行完毕。</p></div></div></div>
              </div>
            </details>

<h2 id="3-取消点"><a href="#3-取消点" class="headerlink" title="3. 取消点"></a><font size=3>3. 取消点</font></h2><h3 id="3-1-取消点的概念"><a href="#3-1-取消点的概念" class="headerlink" title="3.1 取消点的概念"></a><font size=3>3.1 取消点的概念</font></h3><p>终于到了这一部分的笔记了，前边的关于线程取消的函数都是与取消点相关，现在就来了解一下这到底是什么吧。</p>
<p>前边知道若将线程的取消性类型设置为 PTHREAD_CANCEL_DEFERRED 时（线程可以取消状态下），收到其它线程发送过来的取消请求时，仅当线程抵达某个取消点时，取消请求才会起作用。</p>
<p>所谓<strong>取消点其实就是一系列函数</strong>，当执行到这些函数的时候，才会真正响应取消请求，这些函数就是取消点；在没有出现取消点时，取消请求是无法得到处理的。这是因为系统认为，即便收到了取消请求，但是没有到达取消点时，线程正在执行的工作是不能被停止的，正在执行关键代码，此时终止线程将可能会导致出现意想不到的异常发生。</p>
<h3 id="3-2-取消点函数"><a href="#3-2-取消点函数" class="headerlink" title="3.2 取消点函数"></a><font size=3>3.2 取消点函数</font></h3><p>关于取消点函数，我们在 Linux 下可以使用 man 7 pthreads 进行查看，取消点函数主要是帮助手册的 Cancellation points 部分。下边仅仅是罗列写这篇笔记时， Ubuntu21.04 中 man 手册上显示的取消点函数，只是便于自己查看，最好还是直接查 man 手册吧( POSIX.1-2001 and&#x2F;or POSIX.1-2008 )。</p>
<ul>
<li>在 POSIX.1-2001 and&#x2F;or POSIX.1-2008 中必须是取消点的函数</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看函数列表 </summary>
              <div class='content'>
              <table>    <tr><td align="left">accept()         </td><td align="left">getpmsg()        </td><td align="left">open()                  </td><td align="left">putmsg()        </td><td align="left">sem_wait()    </td><td align="left">system() </td></tr><tr><td align="left">aio_suspend()    </td><td align="left">lockf()          </td><td align="left">openat()                </td><td align="left">putpmsg()       </td><td align="left">send()        </td><td align="left">tcdrain()</td></tr><tr><td align="left">clock_nanosleep()</td><td align="left">mq_receive()     </td><td align="left">pause()                 </td><td align="left">pwrite()        </td><td align="left">sendmsg()     </td><td align="left">usleep() </td></tr><tr><td align="left">close()          </td><td align="left">mq_send()        </td><td align="left">poll()                  </td><td align="left">read()          </td><td align="left">sendto()      </td><td align="left">wait()   </td></tr><tr><td align="left">connect()        </td><td align="left">mq_timedreceive()</td><td align="left">pread()                 </td><td align="left">readv()         </td><td align="left">sigpause()    </td><td align="left">waitid() </td></tr><tr><td align="left">creat()          </td><td align="left">mq_timedsend()   </td><td align="left">pselect()               </td><td align="left">recv()          </td><td align="left">sigsuspend()  </td><td align="left">waitpid()</td></tr>    <tr><td align="left">fcntl()          </td><td align="left">msgrcv()         </td><td align="left">pthread_cond_timedwait()</td><td align="left">recvfrom()      </td><td align="left">sigtimedwait()</td><td align="left">write()  </td></tr>    <tr><td align="left">fdatasync()      </td><td align="left">msgsnd()         </td><td align="left">pthread_cond_wait()     </td><td align="left">recvmsg()       </td><td align="left">sigwait()     </td><td align="left">writev() </td></tr>    <tr><td align="left">fsync()          </td><td align="left">msync()          </td><td align="left">pthread_join()          </td><td align="left">select()        </td><td align="left">sigwaitinfo() </td><td align="left">         </td></tr>    <tr><td align="left">getmsg()         </td><td align="left">nanosleep()      </td><td align="left">pthread_testcancel()    </td><td align="left">sem_timedwait() </td><td align="left">sleep()       </td><td align="left">         </td></tr></table><p><strong>【说明】</strong></p><p>（1）以下函数有备注，上边为了不占篇幅，将备注删去了</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">fcntl()    F_SETLKW</span><br><span class="line"><span class="title function_">lockf</span><span class="params">()</span>    F_LOCK</span><br><span class="line"><span class="title function_">openat</span><span class="params">()</span>   [Added in POSIX.1-2008]</span><br><span class="line"><span class="title function_">sigpause</span><span class="params">()</span> [POSIX.1-2001 <span class="title function_">only</span> <span class="params">(moves to <span class="string">&quot;may&quot;</span> <span class="built_in">list</span> in POSIX<span class="number">.1</span><span class="number">-2008</span>)</span>]</span><br><span class="line"><span class="title function_">usleep</span><span class="params">()</span>   [POSIX.1-2001 <span class="title function_">only</span> <span class="params">(function removed in POSIX<span class="number">.1</span><span class="number">-2008</span>)</span>]</span><br></pre></td></tr></table></figure><p>（2）还有一部分函数在 POSIX.1-2001 and&#x2F;or POSIX.1-2008 可能是取消点函数，这些函数较多吗，这里就不写了，可以在 Ubuntu 中使用 man 7 pthreads 查看 Cancellation points 部分。</p>
              </div>
            </details>

<h3 id="3-3-取消点函数执行嘛？"><a href="#3-3-取消点函数执行嘛？" class="headerlink" title="3.3 取消点函数执行嘛？"></a><font size=3>3.3 取消点函数执行嘛？</font></h3><p>这个问题嘛，仅仅是记录自己的一个测试例程，上边我们知道 printf 函数就属于取消点函数，所以我们可以使用该函数进行一个测试。</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span><span class="comment">/* pthread_create pthread_exit pthread_cancel pthread_testcancel pthread_self*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> macro 0</span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCancelType</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="type">pthread_t</span> tid;</span><br><span class="line">	<span class="type">void</span> *retv;</span><br><span class="line">	<span class="comment">/* 1. 创建一个线程 */</span></span><br><span class="line">	ret = pthread_create(&amp;tid, <span class="literal">NULL</span>, (<span class="type">void</span> *)threadCancelType, <span class="literal">NULL</span>);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is main thread,ret=%d,tid=%lu\n&quot;</span>, ret, tid);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">2</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;main thread!i=%d\n&quot;</span>, i);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 2. 申请取消线程 */</span></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;----------------\ncancel thread!\n----------------\n&quot;</span>);</span><br><span class="line">	pthread_cancel(tid);</span><br><span class="line">	<span class="comment">/* 3. 回收线程,若取消成功，这里将会返回错误，然后打印信息 */</span></span><br><span class="line">	ret = pthread_join(tid, &amp;retv);</span><br><span class="line">	<span class="keyword">if</span>(ret != <span class="number">0</span>)</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;pthread_join error: %s\n&quot;</span>, strerror(ret));</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;thread test end, code=%ld\n&quot;</span>, (<span class="type">long</span>)retv);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCancelType</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is a thread test!\n&quot;</span>);</span><br><span class="line">	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,<span class="literal">NULL</span>); <span class="comment">/* 设置为到取消点取消 */</span></span><br><span class="line">	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, <span class="literal">NULL</span>);<span class="comment">/* 设置为不可被取消 */</span></span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;new pthread!i=%d\n&quot;</span>, i);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, <span class="literal">NULL</span>);<span class="comment">/* 设置为可被取消 */</span></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;I&#x27;m printf() Cancellation points!\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> (<span class="type">void</span> *)<span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall -l pthread # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">This is main thread,ret=0,tid=139932233295424</span><br><span class="line">This is a thread test!</span><br><span class="line">new pthread!i=0</span><br><span class="line">main thread!i=0</span><br><span class="line">new pthread!i=1</span><br><span class="line">new pthread!i=2</span><br><span class="line">main thread!i=1</span><br><span class="line">----------------</span><br><span class="line">cancel thread!</span><br><span class="line">----------------</span><br><span class="line">new pthread!i=3</span><br><span class="line">new pthread!i=4</span><br><span class="line">I&#x27;m printf() Cancellation points!</span><br><span class="line">thread test end, code=-1</span><br></pre></td></tr></table></figure><p>这说明取消点函数是执行完毕后退出的。</p>
              </div>
            </details>

<h3 id="3-4-添加取消点"><a href="#3-4-添加取消点" class="headerlink" title="3.4 添加取消点"></a><font size=3>3.4 添加取消点</font></h3><p>假设线程执行的是一个不含取消点的循环（譬如 for 循环、 while 循环），那么这时线程永远也不会响应取消请求，也就意味着除了线程自己主动退出，其它线程将无法通过向它发送取消请求而终止它，，但实际需求是，该线程必须可以被其它线程通过发送取消请求的方式终止，那这个时候怎么办？此时可以使用 pthread_testcancel() ，该函数目的很简单，就是产生一个取消点，线程如果已有处于挂起状态的取消请求，那么只要调用该函数，线程就会随之终止。</p>
<h4 id="3-4-1-pthread-testcancel"><a href="#3-4-1-pthread-testcancel" class="headerlink" title="3.4.1 pthread_testcancel() "></a><font size=3>3.4.1 pthread_testcancel() </font></h4><h5 id="3-4-1-1-函数说明"><a href="#3-4-1-1-函数说明" class="headerlink" title="3.4.1.1 函数说明"></a><font size=3>3.4.1.1 函数说明</font></h5><p>在 linux 下可以使用 man pthread_testcancel 命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Compile and link with -pthread. */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"><span class="type">void</span> <span class="title function_">pthread_testcancel</span><span class="params">(<span class="type">void</span>)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>设置一个取消点。</p>
<p><strong>【函数参数】</strong> none </p>
<p><strong>【返回值】</strong> none </p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">pthread_testcancel()</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong> none </p>
<h5 id="3-4-1-2-使用实例"><a href="#3-4-1-2-使用实例" class="headerlink" title="3.4.1.2 使用实例"></a><font size=3>3.4.1.2 使用实例</font></h5><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span><span class="comment">/* pthread_create pthread_exit pthread_cancel pthread_testcancel pthread_self*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> macro 0</span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCancelType</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="type">pthread_t</span> tid;</span><br><span class="line">	<span class="type">void</span> *retv;</span><br><span class="line">	<span class="comment">/* 1. 创建一个线程 */</span></span><br><span class="line">	ret = pthread_create(&amp;tid, <span class="literal">NULL</span>, (<span class="type">void</span> *)threadCancelType, <span class="literal">NULL</span>);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is main thread,ret=%d,tid=%lu\n&quot;</span>, ret, tid);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">2</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;main thread!i=%d\n&quot;</span>, i);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 2. 申请取消线程 */</span></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;----------------\ncancel thread!\n----------------\n&quot;</span>);</span><br><span class="line">	pthread_cancel(tid);</span><br><span class="line">	<span class="comment">/* 3. 回收线程,若取消成功，这里将会返回错误，然后打印信息 */</span></span><br><span class="line">	ret = pthread_join(tid, &amp;retv);</span><br><span class="line">	<span class="keyword">if</span>(ret != <span class="number">0</span>)</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;pthread_join error: %s\n&quot;</span>, strerror(ret));</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;thread test end, code=%ld\n&quot;</span>, (<span class="type">long</span>)retv);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCancelType</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is a thread test!\n&quot;</span>);</span><br><span class="line">	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,<span class="literal">NULL</span>);<span class="comment">/* 到达取消点取消 */</span></span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 屏蔽 sleep printf两个函数的取消点功能 */</span></span><br><span class="line">		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, <span class="literal">NULL</span>);<span class="comment">/* 设置为不可被取消 */</span></span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;new thread!i=%d\n&quot;</span>, i);</span><br><span class="line">		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, <span class="literal">NULL</span>);<span class="comment">/* 设置为可被取消 */</span></span><br><span class="line">		<span class="comment">/* 设置取消点 */</span></span><br><span class="line">		<span class="keyword">if</span>(i++ == <span class="number">6</span> &amp;&amp; macro == <span class="number">1</span>)</span><br><span class="line">			pthread_testcancel();</span><br><span class="line">		</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> (<span class="type">void</span> *)<span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>程序中的宏 macro 用于配置新线程的取消类型。</p><ul><li>若 macro 为 1 ，则新线程自己添加一个取消点。</li><li>若 macro 为 0 ，则新线程不设置取消点。</li></ul><div class="tabs" id="tabname4"><ul class="nav-tabs"><li class="tab active"><a href="#tabname4-1">macro == 1</a></li><li class="tab"><a href="#tabname4-2">macro == 0</a></li></ul><div class="tab-content"><div class="tab-pane active" id="tabname4-1"><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall -l pthread # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">This is main thread,ret=0,tid=140083039794752</span><br><span class="line">This is a thread test!</span><br><span class="line">main thread!i=0</span><br><span class="line">new thread!i=0</span><br><span class="line">main thread!i=1</span><br><span class="line">----------------</span><br><span class="line">cancel thread!</span><br><span class="line">----------------</span><br><span class="line">new thread!i=1</span><br><span class="line">new thread!i=2</span><br><span class="line">new thread!i=3</span><br><span class="line">new thread!i=4</span><br><span class="line">new thread!i=5</span><br><span class="line">new thread!i=6</span><br><span class="line">thread test end, code=-1</span><br></pre></td></tr></table></figure><p>这个时候，当 i &#x3D; 6 的时候设置取消点，线程被取消。</p></div><div class="tab-pane" id="tabname4-2"><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall -l pthread # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">This is main thread,ret=0,tid=140136216446528</span><br><span class="line">This is a thread test!</span><br><span class="line">new thread!i=0</span><br><span class="line">main thread!i=0</span><br><span class="line">main thread!i=1</span><br><span class="line">----------------</span><br><span class="line">cancel thread!</span><br><span class="line">----------------</span><br><span class="line">new thread!i=1</span><br><span class="line">new thread!i=2</span><br><span class="line">new thread!i=3</span><br><span class="line">new thread!i=4</span><br><span class="line">new thread!i=5</span><br><span class="line">new thread!i=6</span><br><span class="line">new thread!i=7</span><br><span class="line">new thread!i=8</span><br></pre></td></tr></table></figure><p>此种情况中，新线程是无法被取消的。</p></div></div></div>
              </div>
            </details>

<h1 id="二、线程清理"><a href="#二、线程清理" class="headerlink" title="二、线程清理"></a><font size=3>二、线程清理</font></h1><p>前边学习了 atexit() 函数，使用 atexit() 函数注册进程终止处理函数，当进程调用 exit() 退出时就会执行进程终止处理函数；其实，当线程退出时也可以这样做，当线程终止退出时，去执行这样的处理函数，我们把这个函数称为<strong>线程清理函数</strong>（ thread cleanup handler ）。</p>
<p>一个线程可以注册多个清理函数，这些清理函数记录在栈中，每个线程都可以拥有一个清理函数栈，栈是一种<strong>先进后出</strong>的数据结构，也就是说它们的<strong>执行顺序与注册（添加）顺序相反</strong>，当执行完所有清理函数后，线程终止。</p>
<p>【注意事项】同一个清理函数可以被注册多次，满足执行条件的话注册多少次就会执行多少次。</p>
<h2 id="1-函数说明"><a href="#1-函数说明" class="headerlink" title="1.函数说明"></a><font size=3>1.函数说明</font></h2><h3 id="1-1-pthread-cleanup-push"><a href="#1-1-pthread-cleanup-push" class="headerlink" title="1.1 pthread_cleanup_push() "></a><font size=3>1.1 pthread_cleanup_push() </font></h3><p>在 linux 下可以使用 man pthread_cleanup_push 命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Compile and link with -pthread. */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"><span class="type">void</span> <span class="title function_">pthread_cleanup_push</span><span class="params">(<span class="type">void</span> (*routine)(<span class="type">void</span> *), <span class="type">void</span> *arg)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数向清理函数栈中添加一个清理函数。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li>routine ：是一个函数指针变量指向一个 routine() 函数，其中 routine() 函数无返回值，且只有一个 void * 类型参数。</li>
<li>arg ： void * 类型，当调用清理函数 routine() 时，将 arg 作为 routine() 函数的参数。</li>
</ul>
<p><strong>【返回值】</strong> none </p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">pthread_cleanup_push(cleanup, <span class="literal">NULL</span>);</span><br><span class="line">pthread_cleanup_pop(<span class="number">0</span>);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong>必须和 pthread_cleanup_pop() 成对使用。</p>
<h3 id="1-2-pthread-cleanup-pop"><a href="#1-2-pthread-cleanup-pop" class="headerlink" title="1.2 pthread_cleanup_pop() "></a><font size=3>1.2 pthread_cleanup_pop() </font></h3><p>在 linux 下可以使用 man pthread_cleanup_pop 命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Compile and link with -pthread. */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"><span class="type">void</span> <span class="title function_">pthread_cleanup_pop</span><span class="params">(<span class="type">int</span> execute)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数将清理函数栈中最顶层（也就是最后添加的函数，最后入栈）的函数移除。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li>execute ： int 类型，如果为 0 ，清理函数不会被调用，只是将清理函数栈中最顶层的函数移除；如果参数 execute 为非 0 ，则除了将清理函数栈中最顶层的函数移除之外，还会执行相应的清理函数。</li>
</ul>
<p><strong>【返回值】</strong> none </p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">pthread_cleanup_push(cleanup, <span class="literal">NULL</span>);</span><br><span class="line">pthread_cleanup_pop(<span class="number">0</span>);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong>必须和 pthread_cleanup_pop() 成对使用。</p>
<h2 id="2-函数使用"><a href="#2-函数使用" class="headerlink" title="2. 函数使用"></a><font size=3>2. 函数使用</font></h2><h3 id="2-1-函数实现方式"><a href="#2-1-函数实现方式" class="headerlink" title="2.1 函数实现方式"></a><font size=3>2.1 函数实现方式</font></h3><p>上边介绍完了那两个函数，接下来先踩一个坑，就是这俩函数为啥必须成对出现？为啥有几个 pthread_cleanup_push 就要有几个 pthread_cleanup_pop() 呢？</p>
<p>我们来查一下这两个函数的实现( pthread.h )：</p>
<details class="folding-tag" blue><summary> 点击查看实现方式 </summary>
              <div class='content'>
              <figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#  <span class="keyword">define</span> pthread_cleanup_push(routine, arg) \</span></span><br><span class="line"><span class="meta">  do &#123;									      \</span></span><br><span class="line"><span class="meta">    struct __pthread_cleanup_frame __clframe				      \</span></span><br><span class="line"><span class="meta">      __attribute__ ((__cleanup__ (__pthread_cleanup_routine)))		      \</span></span><br><span class="line"><span class="meta">      = &#123; .__cancel_routine = (routine), .__cancel_arg = (arg),	 	      \</span></span><br><span class="line"><span class="meta">	  .__do_it = 1 &#125;;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Remove a cleanup handler installed by the matching pthread_cleanup_push.</span></span><br><span class="line"><span class="comment">   If EXECUTE is non-zero, the handler function is called. */</span></span><br><span class="line"><span class="meta">#  <span class="keyword">define</span> pthread_cleanup_pop(execute) \</span></span><br><span class="line"><span class="meta">    __clframe.__do_it = (execute);					      \</span></span><br><span class="line"><span class="meta">  &#125; while (0)</span></span><br></pre></td></tr></table></figure>
              </div>
            </details>

<p>尽管上面我们将 pthread_cleanup_push() 和 pthread_cleanup_pop() 称之为函数，但它们是通过宏来实现，可展开为分别由 { 和 } 所包裹的语句序列，所以必须在与线程相同的作用域中以匹配对的形式使用，必须一一对应着来使用。</p>
<p>当我们只使用 pthread_cleanup_push() 函数时，程序可能会报以下错误：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">error: expected declaration or statement at end of input</span><br></pre></td></tr></table></figure>

<h3 id="2-2-函数执行条件"><a href="#2-2-函数执行条件" class="headerlink" title="2.2 函数执行条件"></a><font size=3>2.2 函数执行条件</font></h3><p>线程清理函数执行的条件：</p>
<p>（1）线程调用 pthread_exit() 退出时。</p>
<p>（2）线程响应取消请求时。</p>
<p>（3）用非 0 参数调用 pthread_cleanup_pop() 。</p>
<p>除了以上三种情况之外，其它方式终止线程将不会执行线程清理函数，例如在某线程函数start中执行 return 语句退出时就不会执行清理函数。</p>
<h3 id="2-3-pthread-exit-触发清理函数实例"><a href="#2-3-pthread-exit-触发清理函数实例" class="headerlink" title="2.3 pthread_exit() 触发清理函数实例"></a><font size=3>2.3 pthread_exit() 触发清理函数实例</font></h3><details class="folding-tag" blue><summary> 点击查看 pthread_exit() 触发清理函数实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span><span class="comment">/* pthread_create pthread_exit pthread_cancel pthread_setcancelstate*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCleanUp</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">threadCleanUp1</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">threadCleanUp2</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret;</span><br><span class="line">	<span class="type">pthread_t</span> tid;</span><br><span class="line">	<span class="type">void</span> *retv;</span><br><span class="line">	<span class="comment">/* 1. 创建一个线程 */</span></span><br><span class="line">	ret = pthread_create(&amp;tid, <span class="literal">NULL</span>, threadCleanUp, <span class="literal">NULL</span>);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is main thread,ret=%d,tid=%lu\n&quot;</span>, ret, tid);</span><br><span class="line">	sleep(<span class="number">1</span>);</span><br><span class="line">	<span class="comment">/* 2. 回收线程,若取消成功，这里将会返回错误，然后打印信息 */</span></span><br><span class="line">	ret = pthread_join(tid, &amp;retv);</span><br><span class="line">	<span class="keyword">if</span>(ret != <span class="number">0</span>)</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;pthread_join error: %s\n&quot;</span>, strerror(ret));</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;thread test end, code=%ld\n&quot;</span>, (<span class="type">long</span>)retv);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCleanUp</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	pthread_cleanup_push(threadCleanUp1,<span class="string">&quot;threadCleanUp1 runing!&quot;</span>);</span><br><span class="line">	pthread_cleanup_push(threadCleanUp2,<span class="string">&quot;threadCleanUp2 runing!&quot;</span>);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is a new thread!\n&quot;</span>);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;thread runing[%d]!\n&quot;</span>, i);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;<span class="built_in">printf</span>(<span class="string">&quot;The new thread is ready to exit!\n&quot;</span>);</span><br><span class="line">	pthread_exit(<span class="string">&quot;thread return&quot;</span>);</span><br><span class="line">	pthread_cleanup_pop(<span class="number">0</span>);</span><br><span class="line">	pthread_cleanup_pop(<span class="number">0</span>);</span><br><span class="line">	<span class="keyword">return</span> (<span class="type">void</span> *)<span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">threadCleanUp1</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;threadCleanUp1,arg=%s\n&quot;</span>, (<span class="type">char</span>*)arg);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">threadCleanUp2</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;threadCleanUp2,arg=%s\n&quot;</span>, (<span class="type">char</span>*)arg);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall -l pthread # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">This is main thread,ret=0,tid=140032863184448</span><br><span class="line">This is a new thread!</span><br><span class="line">thread runing[0]!</span><br><span class="line">thread runing[1]!</span><br><span class="line">thread runing[2]!</span><br><span class="line">thread runing[3]!</span><br><span class="line">thread runing[4]!</span><br><span class="line">The new thread is ready to exit!</span><br><span class="line">threadCleanUp2,arg=threadCleanUp2 runing!</span><br><span class="line">threadCleanUp1,arg=threadCleanUp1 runing!</span><br><span class="line">thread test end, code=93830143500505</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="2-4-pthread-cancel-触发清理函数实例"><a href="#2-4-pthread-cancel-触发清理函数实例" class="headerlink" title="2.4 pthread_cancel() 触发清理函数实例"></a><font size=3>2.4 pthread_cancel() 触发清理函数实例</font></h3><details class="folding-tag" blue><summary> 点击查看 pthread_cancel() 触发清理函数实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span><span class="comment">/* pthread_create pthread_exit pthread_cancel pthread_setcancelstate*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCleanUp</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">threadCleanUp1</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">threadCleanUp2</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="type">pthread_t</span> tid;</span><br><span class="line">	<span class="type">void</span> *retv;</span><br><span class="line">	<span class="comment">/* 1. 创建一个线程 */</span></span><br><span class="line">	ret = pthread_create(&amp;tid, <span class="literal">NULL</span>, threadCleanUp, <span class="literal">NULL</span>);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is main thread,ret=%d,tid=%lu\n&quot;</span>, ret, tid);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">2</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;main thread!i=%d\n&quot;</span>, i);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">/* 2. 申请取消线程 */</span></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;----------------\ncancel thread!\n----------------\n&quot;</span>);</span><br><span class="line">	pthread_cancel(tid);</span><br><span class="line">	<span class="comment">/* 3. 回收线程,若取消成功，这里将会返回错误，然后打印信息 */</span></span><br><span class="line">	ret = pthread_join(tid, &amp;retv);</span><br><span class="line">	<span class="keyword">if</span>(ret != <span class="number">0</span>)</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;pthread_join error: %s\n&quot;</span>, strerror(ret));</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;thread test end, code=%ld\n&quot;</span>, (<span class="type">long</span>)retv);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCleanUp</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	pthread_cleanup_push(threadCleanUp1,<span class="string">&quot;threadCleanUp1 runing!&quot;</span>);</span><br><span class="line">	pthread_cleanup_push(threadCleanUp2,<span class="string">&quot;threadCleanUp2 runing!&quot;</span>);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is a thread test!\n&quot;</span>);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;thread runing[%d]!\n&quot;</span>, i);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	pthread_cleanup_pop(<span class="number">0</span>);</span><br><span class="line">	pthread_cleanup_pop(<span class="number">0</span>);</span><br><span class="line">	<span class="keyword">return</span> (<span class="type">void</span> *)<span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">threadCleanUp1</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;threadCleanUp1,arg=%s\n&quot;</span>,(<span class="type">char</span>*)arg);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">threadCleanUp2</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;threadCleanUp2,arg=%s\n&quot;</span>,(<span class="type">char</span>*)arg);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall -l pthread # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">This is main thread,ret=0,tid=139866019890752</span><br><span class="line">main thread!i=0</span><br><span class="line">This is a thread test!</span><br><span class="line">thread runing[0]!</span><br><span class="line">main thread!i=1</span><br><span class="line">thread runing[1]!</span><br><span class="line">----------------</span><br><span class="line">cancel thread!</span><br><span class="line">----------------</span><br><span class="line">thread runing[2]!</span><br><span class="line">threadCleanUp2,arg=threadCleanUp2 runing!</span><br><span class="line">threadCleanUp1,arg=threadCleanUp1 runing!</span><br><span class="line">thread test end, code=-1</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看 用非 0 参数调用 pthread_cleanup_pop() 触发清理函数实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span><span class="comment">/* pthread_create pthread_exit pthread_cancel pthread_setcancelstate*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCleanUp</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">threadCleanUp1</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">threadCleanUp2</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret;</span><br><span class="line">	<span class="type">pthread_t</span> tid;</span><br><span class="line">	<span class="type">void</span> *retv;</span><br><span class="line">	<span class="comment">/* 1. 创建一个线程 */</span></span><br><span class="line">	ret = pthread_create(&amp;tid, <span class="literal">NULL</span>, threadCleanUp, <span class="literal">NULL</span>);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is main thread,ret=%d,tid=%lu\n&quot;</span>, ret, tid);</span><br><span class="line"></span><br><span class="line">	sleep(<span class="number">2</span>);<span class="comment">/* 这里停留一下，创建的线程才有时间运行 */</span></span><br><span class="line">	<span class="comment">/* 2. 回收线程,若取消成功，这里将会返回错误，然后打印信息 */</span></span><br><span class="line">	ret = pthread_join(tid, &amp;retv);</span><br><span class="line">	<span class="keyword">if</span>(ret != <span class="number">0</span>)</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;pthread_join error: %s\n&quot;</span>, strerror(ret));</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;thread test end, code=%ld\n&quot;</span>, (<span class="type">long</span>)retv);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">threadCleanUp</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	pthread_cleanup_push(threadCleanUp1,<span class="string">&quot;threadCleanUp1 runing!&quot;</span>);</span><br><span class="line">	pthread_cleanup_push(threadCleanUp2,<span class="string">&quot;threadCleanUp2 runing!&quot;</span>);</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;This is a thread test!\n&quot;</span>);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;thread runing[%d]!\n&quot;</span>, i);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	pthread_cleanup_pop(<span class="number">0</span>);</span><br><span class="line">	pthread_cleanup_pop(<span class="number">1</span>);<span class="comment">/* 只执行这个回调函数 */</span></span><br><span class="line">	<span class="keyword">return</span> (<span class="type">void</span> *)<span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">threadCleanUp1</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;threadCleanUp1,arg=%s\n&quot;</span>,(<span class="type">char</span>*)arg);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">threadCleanUp2</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;threadCleanUp2,arg=%s\n&quot;</span>,(<span class="type">char</span>*)arg);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall -l pthread # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">This is main thread,ret=0,tid=140153667556928</span><br><span class="line">This is a thread test!</span><br><span class="line">thread runing[0]!</span><br><span class="line">thread runing[1]!</span><br><span class="line">thread runing[2]!</span><br><span class="line">thread runing[3]!</span><br><span class="line">thread runing[4]!</span><br><span class="line">threadCleanUp1,arg=threadCleanUp1 runing!</span><br><span class="line">thread test end, code=0</span><br></pre></td></tr></table></figure>
              </div>
            </details>

    </div>

    
    
    

    <footer class="post-footer">




    <div>
        
            <div style="text-align:center;color: #ccc;font-size:14px;">
            ----------本文结束
            <i class="fas fa-fan fa-spin" style="color: #FF1493; font-size: 1rem"></i>
            感谢您的阅读----------
            </div>
        
    </div>





  
  <div class="my_post_copyright"> 
    <p><span>文章标题:</span><a href="/post/bf8f116.html">LV05-02-线程-05-线程取消与清理</a></p>
    <p><span>文章作者:</span><a href="/" title="欢迎访问 《苏木》 的学习笔记">苏木</a></p>
    <p><span>发布时间:</span>2023年07月02日 - 21:52</p>
    <p><span>最后更新:</span>2025年06月14日 - 00:25</p>
    <p><span>原始链接:</span><a href="/post/bf8f116.html" title="LV05-02-线程-05-线程取消与清理">https://sumumm.github.io/post/bf8f116.html</a></p>
    <p><span>许可协议:</span><i class="fab fa-creative-commons"></i> <a rel="license" href= "https://creativecommons.org/licenses/by-nc-nd/4.0/" target="_blank" title="Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)">署名-非商业性使用-禁止演绎 4.0 国际</a> 转载请保留原文链接及作者。</p>  
  </div>
  


          <div class="post-tags">
              <a href="/tags/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/" rel="tag"><i class="fa fa-tag"></i> LV05-操作系统</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/post/ca2dc020.html" rel="prev" title="LV05-03-线程同步-01-线程同步基础">
                  <i class="fa fa-angle-left"></i> LV05-03-线程同步-01-线程同步基础
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/post/744eefdb.html" rel="next" title="LV05-02-线程-04-线程分离">
                  LV05-02-线程-04-线程分离 <i class="fa fa-angle-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">

  <div class="copyright">
    &copy; 2017 – 
    <span itemprop="copyrightYear">2025</span>
    <span class="with-love">
      <i class="fa fa-heart"></i>
    </span>
    <span class="author" itemprop="copyrightHolder">苏木</span>
  </div>
<div class="wordcount">
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-line"></i>
    </span>
      <span>站点总字数：</span>
    <span title="站点总字数">3.7m</span>
  </span>
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span>站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">225:26</span>
  </span>
</div>




    <span id="sitetime"></span>
    <script defer language=javascript>
        function siteTime()
        {
            window.setTimeout("siteTime()", 1000);
            var seconds = 1000;
            var minutes = seconds * 60;
            var hours = minutes * 60;
            var days = hours * 24;
            var years = days * 365;
            var today = new Date();
            var todayYear = today.getFullYear();
            var todayMonth = today.getMonth()+1;
            var todayDate = today.getDate();
            var todayHour = today.getHours();
            var todayMinute = today.getMinutes();
            var todaySecond = today.getSeconds();
            /*==================================================
            Date.UTC() -- 返回date对象距世界标准时间(UTC)1970年1月1日午夜之间的毫秒数(时间戳)
            year        - 作为date对象的年份，为4位年份值
            month       - 0-11之间的整数，做为date对象的月份
            day         - 1-31之间的整数，做为date对象的天数
            hours       - 0(午夜24点)-23之间的整数，做为date对象的小时数
            minutes     - 0-59之间的整数，做为date对象的分钟数
            seconds     - 0-59之间的整数，做为date对象的秒数
            microseconds - 0-999之间的整数，做为date对象的毫秒数
            ==================================================*/
            var t1 = Date.UTC(2017, 
                              5, 
                              19, 
                              0, 
                              0, 
                              0); //北京时间
            var t2 = Date.UTC(todayYear,todayMonth,todayDate,todayHour,todayMinute,todaySecond);
            var diff = t2-t1;
            var diffYears = Math.floor(diff/years);
            var diffDays = Math.floor((diff/days)-diffYears*365);
            var diffHours = Math.floor((diff-(diffYears*365+diffDays)*days)/hours);
            var diffMinutes = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours)/minutes);
            var diffSeconds = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours-diffMinutes*minutes)/seconds);
            document.getElementById("sitetime").innerHTML="已在这里 "+diffYears+" 年 "+diffDays+" 天 "+diffHours+" 小时 "+diffMinutes+" 分钟 "+diffSeconds+" 秒";
        }
        siteTime();
    </script>



    </div>
  </footer>

  
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/next-theme-pjax/0.6.0/pjax.min.js" integrity="sha256-vxLn1tSKWD4dqbMRyv940UYw4sXgMtYcK6reefzZrao=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.umd.js" integrity="sha256-ytMJGN3toR+a84u7g7NuHm91VIR06Q41kMWDr2pq7Zo=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lozad.js/1.16.0/lozad.min.js" integrity="sha256-mOFREFhqmHeQbXpK2lp4nA3qooVgACfh88fpJftLBbc=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script><script src="/js/pjax.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>




  <script src="/js/third-party/fancybox.js"></script>

  <script src="/js/third-party/pace.js"></script>


  




  

  <script class="next-config" data-name="enableMath" type="application/json">true</script><script class="next-config" data-name="mathjax" type="application/json">{"enable":true,"tags":"none","js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.js","integrity":"sha256-MASABpB4tYktI2Oitl4t+78w/lyA+D7b/s9GEP0JOGI="}}</script>
<script src="/js/third-party/math/mathjax.js"></script>


 
        <div id="click-show-text"
            data-mobile = false
            data-text = 富强,民主,文明,和谐,自由,平等,公正,法制,爱国,敬业,诚信,友善
            data-fontsize = 15px
            data-random= false>
        </div>
       

      
        <script async src=https://cdn.jsdelivr.net/npm/hexo-next-mouse-effect@latest/click/showText.js></script>
      

      
    




    <script async src="/js/fancybox_param.js"></script>





<!-- APlayer本体 -->



</body>
</html>
